#include "threadPool/threadPool.h"
#include "log/utils/error_utils.h"
#include "db/common/common.h"
#include "epoll/epoll.h"
#include "log/systemLog/systemLog.h"
#include "net/tcp/tcpInit.h"
#include "config/config.h"
#include "threadPool/worker/taskQueue/taskQueue.h"
#include "timeoutManager/timeoutManager.h"
#include "handler/handler.h"
#include "tlv/tlv.h"
#include "token/token.h"
#include "directory/folderStack.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <sys/epoll.h>
#include <strings.h>
#include <sys/timerfd.h>
#include <time.h>

int exit_pipe[2];

session_manager_t g_session_manager;
timeout_manager_t g_timeout_manager;

void signal_handler(int signo)
{
    // 向退出管道写入数据，通知主线程退出
    const char msg = 'Q';
    printf("Received signal %d, notifying main thread to exit\n", signo);
    SYSTEM_LOG_INFO(SYSTEM_ERR_OK, "Received signal %d, notifying main thread to exit", signo);
    write(exit_pipe[1], &msg, sizeof(msg));
}

// 超时回调函数
void handle_connection_timeout(int fd)
{
    printf("Connection on fd %d timed out, closing\n", fd);
    SYSTEM_LOG_INFO(SYSTEM_ERR_OK, "Connection on fd %d timed out, closing", fd);

    // 检查会话是否存在于主线程的管理器中
    user_session_t *session = NULL;
    int ret = session_manager_get_session(&g_session_manager, fd, &session);

    if (ret == 0 && session != NULL)
    {
        // 会话存在，说明这是由主线程管理的短命令连接
        printf("It's a main-thread session, cleaning up...\n");
        // 从 epoll 中删除该 fd 并关闭连接
        epoll_delete_fd(g_epoll_fd, fd);
        close(fd);
        // 调用会话管理器，清理会话数据
        session_manager_remove_session(&g_session_manager, fd);
    }
    else
    {
        // 会话不存在，说明这可能是一个已移交给工作线程的长命令连接
        // 主线程不应该直接关闭它，以避免与工作线程冲突。
        printf("Session not found in main manager, likely a worker-thread fd. Main thread will not close it.\n");
        // 在这种情况下，我们依赖工作线程自身的I/O错误处理（例如recv/send超时或返回错误）来最终关闭连接。
        // 理想的实现是发送一个取消信号给对应的工作线程。
    }
}

int main(void)
{
    // 加载配置
    printf("Loading server configuration...\n");
    server_config_t cfg;
    // 错误处理
    const char *config_path = "config/server.conf";
    printf("Config path: %s\n", config_path);
    CALL_RET_AND_LOG("load_server_config",
                     load_server_config(config_path, &cfg),
                     CONFIG_LOAD_CHECK);
    // 初始化系统日志
    // 错误处理
    printf("Initializing system log at path: %s\n", g_system_log_path);
    CALL_RET_AND_LOG("system_log_init",
                     system_log_init(g_system_log_path, SYSTEM_LOG_LEVEL_DEBUG),
                     LOG_INIT_CHECK);
    printf("System log initialized successfully\n");
    // 创建退出管道
    socketpair(AF_LOCAL, SOCK_STREAM, 0, exit_pipe);
    // 创建主线程和子线程
    // 主线程用来接收退出信号
    if (fork())
    {
        close(exit_pipe[0]);
        signal(SIGUSR1, signal_handler);
        // 主线程等待子线程退出
        wait(NULL);
        // 主线程退出
        close(exit_pipe[1]);
        printf("Main thread exiting\n");
        SYSTEM_LOG_INFO(SYSTEM_ERR_OK, "Main thread exiting");
        exit(0);
    }
    // 子线程用来运行服务器主逻辑
    close(exit_pipe[1]);
    // 创建线程池
    thread_pool_t thread_pool;
    int ret = thread_pool_init(&thread_pool, 4);
    // 错误处理
    if (ret != SYSTEM_ERR_OK)
    {
        SYSTEM_LOG_FATAL(ret, "Failed to initialize thread pool");
        exit(-1);
    }
    printf("Thread pool initialized with 4 workers\n");
    SYSTEM_LOG_INFO(SYSTEM_ERR_OK, "Thread pool initialized with 4 workers");
    // 创建 TCP 监听套接字
    char port_str[6];
    sprintf(port_str, "%d", cfg.server_port);
    int server_fd = tcp_server_init(cfg.server_ip, port_str);
    // 创建会话管理器
    ret = session_manager_init(&g_session_manager, 1024);
    // TODO: 错误处理和统一的错误码以及日志
    printf("Session manager init ret = %d\n", ret);
    // 创建超时管理器
    // 初始化超时管理器，环形队列容量31（约30秒超时），每个哈希集合大小100，全局位置映射大小1024
    ret = timeout_manager_init(&g_timeout_manager, 31, 100, 1024, handle_connection_timeout);
    // TODO: 错误处理和统一的错误码以及日志
    printf("Timeout manager init ret = %d\n", ret);
    // 创建一个1秒触发一次的定时器
    int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
    struct itimerspec timer_spec;
    timer_spec.it_interval.tv_sec = 1; // 间隔1秒
    timer_spec.it_interval.tv_nsec = 0;
    timer_spec.it_value.tv_sec = 1; // 初始触发1秒
    timer_spec.it_value.tv_nsec = 0;
    timerfd_settime(timer_fd, 0, &timer_spec, NULL);
    // 创建epoll实例
    g_epoll_fd = epoll_create_instance(1024);
    // 将计时器，服务器套接字和退出管道加入epoll监听
    epoll_add_fd(g_epoll_fd, timer_fd);
    epoll_add_fd(g_epoll_fd, server_fd);
    epoll_add_fd(g_epoll_fd, exit_pipe[0]);
    // 进入事件循环
    struct epoll_event ready_set[1];
    while (1)
    {
        epoll_wait(g_epoll_fd, ready_set, 1, -1);
        int curfd = ready_set[0].data.fd;
        // 计时器事件，调用超时管理器的tick函数
        if (curfd == timer_fd)
        {
            timeout_manager_tick(&g_timeout_manager);
            // 读取定时器事件，防止重复触发
            uint64_t expirations;
            read(timer_fd, &expirations, sizeof(expirations)); // 读取以清除事件
            continue;
        }
        // 新用户连接
        if (curfd == server_fd)
        {
            // 获取新连接
            int netfd = accept(server_fd, NULL, NULL);
            if (netfd < 0)
            {
                SYSTEM_LOG_ERROR(SYSTEM_ERR_INVALID_ARGUMENT, "Failed to accept new connection");
                continue;
            }
            // 将新连接加入epoll监听
            epoll_add_fd(g_epoll_fd, netfd);
            // 将新连接加入会话管理器
            ret = session_manager_add_session(&g_session_manager, netfd);
            // TODO: 错误处理统一的错误码和日志
            printf("New connection accepted, netfd = %d, session manager add ret = %d\n", netfd, ret);
            // 将新连接加入超时管理器，即更新其活跃时间
            ret = timeout_manager_update_user_activity(&g_timeout_manager, netfd);
            // TODO: 错误处理统一的错误码和日志
            printf("New connection accepted, netfd = %d, timeout manager update ret = %d\n", netfd, ret);
            continue;
        }
        if (curfd == exit_pipe[0])
        {
            // 收到退出信号，通知线程池退出
            printf("Received exit signal, shutting down thread pool\n");
            SYSTEM_LOG_INFO(SYSTEM_ERR_OK, "Received exit signal, shutting down thread pool");
            pthread_mutex_lock(&thread_pool.shared_data.queue_mutex);
            thread_pool.shared_data.exit_flag = 1;
            pthread_cond_broadcast(&thread_pool.shared_data.queue_cond);
            pthread_mutex_unlock(&thread_pool.shared_data.queue_mutex);
            for (int i = 0; i < thread_pool.worker_list.worker_count; i++)
            {
                pthread_join(thread_pool.worker_list.workers[i], NULL);
            }
            // 关闭套接字和epoll实例
            close(server_fd);
            close(g_epoll_fd);
            close(exit_pipe[0]);
            printf("Server shutting down gracefully\n");
            SYSTEM_LOG_INFO(SYSTEM_ERR_OK, "Server shutting down gracefully");
            break;
        }
        // TODO: 短命令处理和长命令下发给线程池处理
        user_session_t *session;
        ret = session_manager_get_session(&g_session_manager, curfd, &session);
        // TODO: 错误处理和统一的错误码以及日志
        if (ret == SYSTEM_ERR_HASHMAP_NOT_FOUND)
        {
            // 未找到会话，可能是无效的文件描述符
            epoll_delete_fd(g_epoll_fd, curfd);
            close(curfd);
            continue;
        }

        // 更新用户活动时间
        timeout_manager_update_user_activity(&g_timeout_manager, curfd);

        tlv_msg_t msg;
        bzero(&msg, sizeof(tlv_msg_t));
        int recv_ret = tlv_recv(curfd, &msg);
        if (recv_ret == 1)
        {
            // 客户端断开
            epoll_delete_fd(g_epoll_fd, curfd);
            close(curfd);
            session_manager_remove_session(&g_session_manager, curfd);
            continue;
        }

        switch (session->state)
        {
        case CONN_STATE_INITIAL:
            // TODO: 保证请求的类型一定正确
            // 通过第一个包中的标志位判断其意图
            // 登录请求就直接交给处理登录请求的函数，它会将状态改为等待密码
            if (msg.hdr.type == DO_LOGIN)
            {
                printf("Processing login request on fd %d\n", curfd);
                if (session->conn == NULL)
                {
                    ret = db_common_mysql_connect(&session->conn);
                    printf("Database connection for login ret = %d\n", ret);
                }
                printf("Login request received on fd %d\n", curfd);
                ret = handle_login_request(session, &msg);
                printf("Handle login request ret = %d\n", ret);
                // 初始化其他会话信息，如路径栈等
                bzero(session->path, sizeof(session->path));
                session->pStack = (folderStack_t *)malloc(sizeof(folderStack_t));
                folderStackInit(session->pStack);
                push(session->pStack, 1); // 根目录入栈
                // TODO: 错误处理
            }
            else if (msg.hdr.type == DO_REGISTER)
            {
                printf("Register request received on fd %d\n", curfd);
                ret = db_common_mysql_connect(&session->conn);
                printf("Database connection for registration ret = %d\n", ret);
                printf("Register request received on fd %d\n", curfd);
                ret = handle_register_request(session);
                // TODO: 错误处理
                printf("Handle register request ret = %d\n", ret);
            }
            // 如果是token验证请求，就交给处理token验证的函数，它会将状态改为已认证
            else if (msg.hdr.type == TOKEN) // 假设是长命令请求
            {
                printf("Long command request received on fd %d\n", curfd);

                // 1. 验证 token 并获取 username
                char *token_username = NULL;
                ret = validate_jwt_and_get_username(msg.value, &token_username);

                if (ret == SYSTEM_ERR_OK && token_username != NULL)
                {
                    // 2. 根据 username 查找主会话
                    user_session_t *main_session = NULL;
                    ret = session_manager_get_session_by_username(&g_session_manager, token_username, &main_session);

                    if (ret == 0 && main_session != NULL)
                    {
                        // 3. 找到了主会话，复制上下文到当前新连接的会话
                        user_session_t *long_cmd_session = session; // 当前新连接的会话
                        long_cmd_session->user_id = main_session->user_id;
                        strcpy(long_cmd_session->username, main_session->username);
                        strcpy(long_cmd_session->path, main_session->path);
                        // 注意：pStack 是指针，需要深拷贝，不能直接赋值
                        // 手动深拷贝栈
                        long_cmd_session->pStack = (folderStack_t *)malloc(sizeof(folderStack_t));
                        if (long_cmd_session->pStack != NULL)
                        {
                            folderStackInit(long_cmd_session->pStack);
                            Node_t *current = main_session->pStack->pTop;
                            Node_t **new_stack_next_ptr = &long_cmd_session->pStack->pTop;
                            while (current != NULL)
                            {
                                Node_t *new_node = (Node_t *)malloc(sizeof(Node_t));
                                if (new_node != NULL)
                                {
                                    new_node->file_id = current->file_id;
                                    new_node->pNext = NULL;
                                    *new_stack_next_ptr = new_node;
                                    new_stack_next_ptr = &new_node->pNext;
                                }
                                current = current->pNext;
                            }
                            long_cmd_session->pStack->stackSize = main_session->pStack->stackSize;
                        }
                        else
                        {
                            // 内存分配失败处理
                            long_cmd_session->pStack = NULL;
                        }
                        long_cmd_session->conn = NULL; // 数据库连接通常是每个线程独立创建

                        printf("Context copied for user %s. Handing over to worker.\n", long_cmd_session->username);

                        // 4. 创建任务并放入线程池
                        task_node_t *task = NULL;
                        task_node_create(long_cmd_session, &task);

                        pthread_mutex_lock(&thread_pool.shared_data.queue_mutex);
                        enqueue_task(&thread_pool.shared_data.task_queue, task);
                        pthread_cond_signal(&thread_pool.shared_data.queue_cond);
                        pthread_mutex_unlock(&thread_pool.shared_data.queue_mutex);

                        // 5. 从主线程的管理中移除这个 fd
                        // 注意：我们不再 remove session，因为 session 的内存所有权已经转移给任务节点
                        epoll_delete_fd(g_epoll_fd, curfd);
                        // 只从 fd_map 中移除，因为 session 本身还要用
                        hash_map_remove(&g_session_manager.fd_map, curfd);
                    }
                    else
                    {
                        // 未找到活动的主会话，可能主连接已断开
                        printf("No active main session found for user %s. Closing.\n", token_username);
                        close(curfd);
                        session_manager_remove_session(&g_session_manager, curfd);
                    }
                    free(token_username);
                }
                else
                {
                    // Token 验证失败
                    // TODO: 可能需要给客户端返回错误信息
                    printf("Token validation failed on fd %d, closing connection\n", curfd);
                    epoll_delete_fd(g_epoll_fd, curfd);
                    close(curfd);
                    session_manager_remove_session(&g_session_manager, curfd);
                }
            }
            else
            {
                // 未知的第一个请求，关闭连接
                // TODO: 暂时这么处理
                printf("Unknown initial request type %d on fd %d. Closing.\n", msg.hdr.type, curfd);
                epoll_delete_fd(g_epoll_fd, curfd);
                close(curfd);
                session_manager_remove_session(&g_session_manager, curfd);
            }
            break;
        case CONN_STATE_AWAITING_LOGIN:
            // ... 实现接收用户名、查库、发盐值逻辑 ...
            // 成功后更新状态: session->state = CONN_STATE_AWAITING_PASSWORD;
            ret = handle_login_request(session, &msg);
            // TODO: 错误处理
            printf("Handle login request ret = %d\n", ret);
            break;
        case CONN_STATE_AWAITING_PASSWORD:
            // ... 实现接收密文、验证、生成并发送 token 逻辑 ...
            // 成功后更新状态: session->state = CONN_STATE_AUTHENTICATED;
            ret = handle_password_request(session, &msg);
            // TODO: 错误处理
            printf("Handle password request ret = %d\n", ret);
            break;
        case CONN_STATE_AUTHENTICATED:
            // ... 实现短命令处理逻辑 ...
            ret = handle_short_command_request(session, &msg);
            // TODO: 错误处理
            printf("Handle short command request ret = %d\n", ret);
            break;
        }
        // TODO: 错误处理
    }
    // 子线程退出
    exit(0);

    return 0;
}